#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_ttf.h>

#include "constantes.h"
#include "fichiers.h"
#include "jeu.h"
#include "editeur.h"

#ifdef _PSP_FW_VERSION
#include <pspctrl.h>
#endif

char *itoa(int value, char *str, int radix)
{
    int rem = 0;
    int pos = 0;
    char ch = '!';
    do {
	rem = value % radix;
	value /= radix;
	if (16 == radix) {
	    if (rem >= 10 && rem <= 15) {
		switch (rem) {
		case 10:
		    ch = 'a';
		    break;
		case 11:
		    ch = 'b';
		    break;
		case 12:
		    ch = 'c';
		    break;
		case 13:
		    ch = 'd';
		    break;
		case 14:
		    ch = 'e';
		    break;
		case 15:
		    ch = 'f';
		    break;
		}
	    }
	}
	if ('!' == ch) {
	    str[pos++] = (char) (rem + 0x30);
	} else {
	    str[pos++] = ch;
	}
    }
    while (value != 0);
    str[pos] = '\0';
    return str;
}

void jouer(SDL_Surface * ecran, int level)
{
    SDL_Surface *luigi[4] = { NULL };	// 4 surfaces pour chacune des directions de luigi
    SDL_Surface *mur = NULL, *caisse = NULL, *caisseOK = NULL, *objectif =
	NULL, *luigiActuel = NULL, *texte = NULL;
    SDL_Rect position, positionJoueur, positiontxt;
    TTF_Font *police = NULL;

    char *under = (char *) malloc(100 * sizeof(char));
    under[0] = '\0';
    char *clevel = (char *) malloc(5 * sizeof(char));
    //strcat(under, "Niveau ");
    strcat(under, "Level ");

    itoa(level, clevel, 10);
    strcat(under, clevel);
    TTF_Init();
    police = TTF_OpenFont("alpha.ttf", 40);

    SDL_Color couleurNoire = { 0, 0, 0 };
    texte = TTF_RenderText_Blended(police, under, couleurNoire);

    int continuer = 1, objectifsRestants = 0, i = 0, j = 0;
    int carte[NB_BLOCS_LARGEUR][NB_BLOCS_HAUTEUR] = { {0} };

    // Chargement des sprites (décors, personnage...)
    mur = IMG_Load("mur.jpg");
    caisse = IMG_Load("caisse.jpg");
    caisseOK = IMG_Load("caisseactive.jpg");
    objectif = IMG_Load("objectif.gif");
    luigi[BAS] = IMG_Load("luigiface.gif");
    luigi[GAUCHE] = IMG_Load("luigigauche.gif");
    luigi[HAUT] = IMG_Load("luigihaut.gif");
    luigi[DROITE] = IMG_Load("luigidroite.gif");

    luigiActuel = luigi[BAS];	//Au départ il regarde vers le bas

    if (!chargerNiveau(carte, level))
	exit(EXIT_FAILURE);

    // Recherche de la position de luigi au départ
    for (i = 0; i < NB_BLOCS_HAUTEUR; i++) {
	for (j = 0; j < NB_BLOCS_LARGEUR; j++) {
	    if (carte[i][j] == LUIGI)	// Si luigi se trouve à cette position sur la carte
	    {
		positionJoueur.x = i;
		positionJoueur.y = j;
		SDL_BlitSurface(texte, NULL, ecran, &positiontxt);
		//carte[i][j] = VIDE;
	    }
	}
    }

    SDL_JoystickEventState(SDL_ENABLE);
    SDL_JoystickOpen(0);

    SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
    while (continuer) {
	SDL_Event event;
	while (SDL_PollEvent(&event)) {
	    if (event.type == SDL_JOYBUTTONDOWN) {
		switch (event.jbutton.button) {
		case PSP_BUTTON_B:
		    continuer = 0;
		    break;
		case PSP_BUTTON_UP:
		    luigiActuel = luigi[HAUT];
		    deplacerJoueur(carte, &positionJoueur, HAUT);
		    break;
		case PSP_BUTTON_DOWN:
		    luigiActuel = luigi[BAS];
		    deplacerJoueur(carte, &positionJoueur, BAS);
		    break;
		case PSP_BUTTON_RIGHT:
		    luigiActuel = luigi[DROITE];
		    deplacerJoueur(carte, &positionJoueur, DROITE);
		    break;
		case PSP_BUTTON_LEFT:
		    luigiActuel = luigi[GAUCHE];
		    deplacerJoueur(carte, &positionJoueur, GAUCHE);
		    break;
		case PSP_BUTTON_Y:
		    continuer = 0;

		    free(under);
		    free(clevel);

		    // Libération des surfaces chargées
		    SDL_FreeSurface(mur);
		    SDL_FreeSurface(caisse);
		    SDL_FreeSurface(caisseOK);
		    SDL_FreeSurface(objectif);
		    SDL_FreeSurface(texte);
		    for (i = 0; i < 4; i++)
			SDL_FreeSurface(luigi[i]);

		    jouer(ecran, level);
		    return;
		    break;
		default:
		    break;
		}
	    }
	}

	// Effacement de l'écran
	SDL_FillRect(ecran, NULL,
		     SDL_MapRGB(ecran->format, 255, 255, 255));

	// Placement des objets à l'écran
	objectifsRestants = 0;

	for (i = 0; i < NB_BLOCS_LARGEUR; i++) {
	    for (j = 0; j < NB_BLOCS_HAUTEUR; j++) {
		position.x = i * TAILLE_BLOC + 2;
		position.y = j * TAILLE_BLOC;

		switch (carte[i][j]) {
		case MUR:
		    SDL_BlitSurface(mur, NULL, ecran, &position);
		    break;
		case CAISSE:
		    SDL_BlitSurface(caisse, NULL, ecran, &position);
		    break;
		case CAISSE_OK:
		    SDL_BlitSurface(caisseOK, NULL, ecran, &position);
		    break;
		case OBJECTIF:
		    SDL_BlitSurface(objectif, NULL, ecran, &position);
		    objectifsRestants = 1;
		    break;
		}
	    }
	}

	// On place le joueur à la bonne position
	position.x = positionJoueur.x * TAILLE_BLOC + 2;
	position.y = positionJoueur.y * TAILLE_BLOC;
	SDL_BlitSurface(luigiActuel, NULL, ecran, &position);

	positiontxt.x = 168 + 2 + 6;	// + 2 = décalage ... + 6 = Level au lieu de Niveau
	positiontxt.y = 225;
	SDL_BlitSurface(texte, NULL, ecran, &positiontxt);

	SDL_Flip(ecran);

	if (objectifsRestants == 0) {
	    continuer = 0;
	    if (level < TOTALLEVEL) {
#ifdef _PSP_FW_VERSION
		SDL_Delay(200);
#endif
		free(under);
		free(clevel);

		// Libération des surfaces chargées
		SDL_FreeSurface(mur);
		SDL_FreeSurface(caisse);
		SDL_FreeSurface(caisseOK);
		SDL_FreeSurface(objectif);
		SDL_FreeSurface(texte);
		for (i = 0; i < 4; i++)
		    SDL_FreeSurface(luigi[i]);

		jouer(ecran, level + 1);

		return;
	    }
	}
    }

    // Désactivation de la répétition des touches (remise à 0)
    SDL_EnableKeyRepeat(0, 0);
    SDL_JoystickClose(0);


    if (!continuer) {
	free(under);
	free(clevel);

	// Libération des surfaces chargées
	SDL_FreeSurface(mur);
	SDL_FreeSurface(caisse);
	SDL_FreeSurface(caisseOK);
	SDL_FreeSurface(objectif);
	SDL_FreeSurface(texte);
	for (i = 0; i < 4; i++)
	    SDL_FreeSurface(luigi[i]);
    }
}

int
deplacerJoueur(int carte[][NB_BLOCS_HAUTEUR], SDL_Rect * pos,
	       int direction)
{
    int delay = 0;
    switch (direction) {
    case HAUT:
	if (pos->y - 1 < 0)	// Si le joueur dépasse l'écran, on arrête
	    break;
	if (carte[pos->x][pos->y - 1] == MUR)	// S'il y a un mur, on arrête
	    break;
	// Si on veut pousser une caisse, il faut vérifier qu'il n'y a pas de mur derrière (ou une autre caisse, ou la limite du monde)
	if ((carte[pos->x][pos->y - 1] == CAISSE
	     || carte[pos->x][pos->y - 1] == CAISSE_OK) && (pos->y - 2 < 0
							    || carte[pos->
								     x]
							    [pos->y - 2] ==
							    MUR
							    || carte[pos->
								     x]
							    [pos->y - 2] ==
							    CAISSE
							    || carte[pos->
								     x]
							    [pos->y - 2] ==
							    CAISSE_OK))
	    break;

	// Si on arrive là, c'est qu'on peut déplacer le joueur !
	// On vérifie d'abord s'il y a une caisse à déplacer
	deplacerCaisse(&carte[pos->x][pos->y - 1],
		       &carte[pos->x][pos->y - 2]);

	pos->y--;		// On peut enfin faire monter le joueur (oufff !)
	delay = 1;
	break;

    case BAS:
	if (pos->y + 1 > NB_BLOCS_HAUTEUR)	// Si le joueur dépasse l'écran, on arrête
	    break;
	if (carte[pos->x][pos->y + 1] == MUR)	// S'il y a un mur, on arrête
	    break;
	// Si on veut pousser une caisse, il faut vérifier qu'il n'y a pas de mur derrière (ou une autre caisse, ou la limite du monde)
	if ((carte[pos->x][pos->y + 1] == CAISSE
	     || carte[pos->x][pos->y + 1] == CAISSE_OK)
	    && (pos->y + 2 > NB_BLOCS_HAUTEUR
		|| carte[pos->x][pos->y + 2] == MUR
		|| carte[pos->x][pos->y + 2] == CAISSE
		|| carte[pos->x][pos->y + 2] == CAISSE_OK))
	    break;

	deplacerCaisse(&carte[pos->x][pos->y + 1],
		       &carte[pos->x][pos->y + 2]);

	pos->y++;		// On peut enfin faire monter le joueur (oufff !)
	delay = 1;
	break;

    case GAUCHE:
	if (pos->x - 1 < 0)	// Si le joueur dépasse l'écran, on arrête
	    break;
	if (carte[pos->x - 1][pos->y] == MUR)	// S'il y a un mur, on arrête
	    break;
	// Si on veut pousser une caisse, il faut vérifier qu'il n'y a pas de mur derrière (ou une autre caisse, ou la limite du monde)
	if ((carte[pos->x - 1][pos->y] == CAISSE
	     || carte[pos->x - 1][pos->y] == CAISSE_OK) && (pos->x - 2 < 0
							    || carte[pos->
								     x - 2]
							    [pos->y] == MUR
							    || carte[pos->
								     x - 2]
							    [pos->y] ==
							    CAISSE
							    || carte[pos->
								     x - 2]
							    [pos->y] ==
							    CAISSE_OK))
	    break;

	// Si on arrive làœ, c'est qu'on peut déplacer le joueur !
	// On vérifie d'abord s'il y a une caisse à déplacer
	deplacerCaisse(&carte[pos->x - 1][pos->y],
		       &carte[pos->x - 2][pos->y]);

	pos->x--;		// On peut enfin faire monter le joueur (oufff !)
	delay = 1;
	break;

    case DROITE:
	if (pos->x + 1 > NB_BLOCS_LARGEUR)	// Si le joueur dépasse l'écran, on arrête
	    break;
	if (carte[pos->x + 1][pos->y] == MUR)	// S'il y a un mur, on arrête
	    break;
	// Si on veut pousser une caisse, il faut vérifier qu'il n'y a pas de mur derrière (ou une autre caisse, ou la limite du monde)
	if ((carte[pos->x + 1][pos->y] == CAISSE
	     || carte[pos->x + 1][pos->y] == CAISSE_OK) && (pos->x + 1 < 0
							    || carte[pos->
								     x + 2]
							    [pos->y] == MUR
							    || carte[pos->
								     x + 2]
							    [pos->y] ==
							    CAISSE
							    || carte[pos->
								     x + 2]
							    [pos->y] ==
							    CAISSE_OK))
	    break;

	// Si on arrive là c'est qu'on peut déplacer le joueur !
	// On vérifie d'abord s'il y a une caisse à déplacer
	deplacerCaisse(&carte[pos->x + 1][pos->y],
		       &carte[pos->x + 2][pos->y]);

	pos->x++;		// On peut enfin faire monter le joueur (oufff !)
	delay = 1;
	break;


    }

    return delay;
}


void deplacerCaisse(int *premiereCase, int *secondeCase)
{
    if (*premiereCase == CAISSE || *premiereCase == CAISSE_OK) {
	if (*secondeCase == OBJECTIF)
	    *secondeCase = CAISSE_OK;
	else
	    *secondeCase = CAISSE;

	if (*premiereCase == CAISSE_OK)
	    *premiereCase = OBJECTIF;
	else
	    *premiereCase = VIDE;
    }
}
